Make it possible to specify additional modules to load via a setting.
authorMatthias Clasen <mclasen@redhat.com>
Wed, 1 Sep 2004 20:30:24 +0000 (20:30 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Wed, 1 Sep 2004 20:30:24 +0000 (20:30 +0000)
2004-09-01  Matthias Clasen  <mclasen@redhat.com>

Make it possible to specify additional modules to load
via a setting.  (#117236, Alex Graveley)

* gtk/gtkmodules.h:
* gtk/gtkmodules.c: New files which contain the module
handling code which was previously in gtkmain.[hc].
Additionally, the code now looks for the gtk-modules
setting, which can specify additional modules to load.

* gtk/gtkmain.c:
* gtk/gtkmain.h: Remove all the module handling code.

* gtk/gtkdebug.h: Add a debug flag for modules.

* gtk/gtk.h: Include gtkmodules.h

* gtk/Makefile.am (gtk_public_h_sources): Add gtkmodules.h
(gtk_c_sources): Add gtkmodules.c

* gtk/gtksettings.c: Add the gtk-modules setting.

* gdk/x11/gdkevents-x11.c: Add the Gtk/Modules XSetting.

13 files changed:
ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gdk/x11/gdkevents-x11.c
gtk/Makefile.am
gtk/gtk.h
gtk/gtkdebug.h
gtk/gtkmain.c
gtk/gtkmain.h
gtk/gtkmodules.c [new file with mode: 0644]
gtk/gtkmodules.h [new file with mode: 0644]
gtk/gtksettings.c

index 878d74c522db46beab42bd2d7c71caa5ce9d6801..d25d433d9b9f3d3045145934fbb8e3cc098c3083 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2004-09-01  Matthias Clasen  <mclasen@redhat.com>
+
+       Make it possible to specify additional modules to load
+       via a setting.  (#117236, Alex Graveley)
+       
+       * gtk/gtkmodules.h: 
+       * gtk/gtkmodules.c: New files which contain the module
+       handling code which was previously in gtkmain.[hc]. 
+       Additionally, the code now looks for the gtk-modules 
+       setting, which can specify additional modules to load.
+
+       * gtk/gtkmain.c: 
+       * gtk/gtkmain.h: Remove all the module handling code.
+
+       * gtk/gtkdebug.h: Add a debug flag for modules.
+
+       * gtk/gtk.h: Include gtkmodules.h
+
+       * gtk/Makefile.am (gtk_public_h_sources): Add gtkmodules.h
+       (gtk_c_sources): Add gtkmodules.c
+
+       * gtk/gtksettings.c: Add the gtk-modules setting.
+
+       * gdk/x11/gdkevents-x11.c: Add the Gtk/Modules XSetting.
+
 Wed Sep  1 19:11:44 2004  Søren Sandmann  <sandmann@redhat.com>
 
        * gtk/gtktoolbar.c (gtk_toolbar_size_allocate): Make sure
index 878d74c522db46beab42bd2d7c71caa5ce9d6801..d25d433d9b9f3d3045145934fbb8e3cc098c3083 100644 (file)
@@ -1,3 +1,28 @@
+2004-09-01  Matthias Clasen  <mclasen@redhat.com>
+
+       Make it possible to specify additional modules to load
+       via a setting.  (#117236, Alex Graveley)
+       
+       * gtk/gtkmodules.h: 
+       * gtk/gtkmodules.c: New files which contain the module
+       handling code which was previously in gtkmain.[hc]. 
+       Additionally, the code now looks for the gtk-modules 
+       setting, which can specify additional modules to load.
+
+       * gtk/gtkmain.c: 
+       * gtk/gtkmain.h: Remove all the module handling code.
+
+       * gtk/gtkdebug.h: Add a debug flag for modules.
+
+       * gtk/gtk.h: Include gtkmodules.h
+
+       * gtk/Makefile.am (gtk_public_h_sources): Add gtkmodules.h
+       (gtk_c_sources): Add gtkmodules.c
+
+       * gtk/gtksettings.c: Add the gtk-modules setting.
+
+       * gdk/x11/gdkevents-x11.c: Add the Gtk/Modules XSetting.
+
 Wed Sep  1 19:11:44 2004  Søren Sandmann  <sandmann@redhat.com>
 
        * gtk/gtktoolbar.c (gtk_toolbar_size_allocate): Make sure
index 878d74c522db46beab42bd2d7c71caa5ce9d6801..d25d433d9b9f3d3045145934fbb8e3cc098c3083 100644 (file)
@@ -1,3 +1,28 @@
+2004-09-01  Matthias Clasen  <mclasen@redhat.com>
+
+       Make it possible to specify additional modules to load
+       via a setting.  (#117236, Alex Graveley)
+       
+       * gtk/gtkmodules.h: 
+       * gtk/gtkmodules.c: New files which contain the module
+       handling code which was previously in gtkmain.[hc]. 
+       Additionally, the code now looks for the gtk-modules 
+       setting, which can specify additional modules to load.
+
+       * gtk/gtkmain.c: 
+       * gtk/gtkmain.h: Remove all the module handling code.
+
+       * gtk/gtkdebug.h: Add a debug flag for modules.
+
+       * gtk/gtk.h: Include gtkmodules.h
+
+       * gtk/Makefile.am (gtk_public_h_sources): Add gtkmodules.h
+       (gtk_c_sources): Add gtkmodules.c
+
+       * gtk/gtksettings.c: Add the gtk-modules setting.
+
+       * gdk/x11/gdkevents-x11.c: Add the Gtk/Modules XSetting.
+
 Wed Sep  1 19:11:44 2004  Søren Sandmann  <sandmann@redhat.com>
 
        * gtk/gtktoolbar.c (gtk_toolbar_size_allocate): Make sure
index 878d74c522db46beab42bd2d7c71caa5ce9d6801..d25d433d9b9f3d3045145934fbb8e3cc098c3083 100644 (file)
@@ -1,3 +1,28 @@
+2004-09-01  Matthias Clasen  <mclasen@redhat.com>
+
+       Make it possible to specify additional modules to load
+       via a setting.  (#117236, Alex Graveley)
+       
+       * gtk/gtkmodules.h: 
+       * gtk/gtkmodules.c: New files which contain the module
+       handling code which was previously in gtkmain.[hc]. 
+       Additionally, the code now looks for the gtk-modules 
+       setting, which can specify additional modules to load.
+
+       * gtk/gtkmain.c: 
+       * gtk/gtkmain.h: Remove all the module handling code.
+
+       * gtk/gtkdebug.h: Add a debug flag for modules.
+
+       * gtk/gtk.h: Include gtkmodules.h
+
+       * gtk/Makefile.am (gtk_public_h_sources): Add gtkmodules.h
+       (gtk_c_sources): Add gtkmodules.c
+
+       * gtk/gtksettings.c: Add the gtk-modules setting.
+
+       * gdk/x11/gdkevents-x11.c: Add the Gtk/Modules XSetting.
+
 Wed Sep  1 19:11:44 2004  Søren Sandmann  <sandmann@redhat.com>
 
        * gtk/gtktoolbar.c (gtk_toolbar_size_allocate): Make sure
index 733fd568450a72a4e12561868f1bbdc6fdfe7eae..bb121dc22d2141b6c52b42c763a8d91897306c9d 100644 (file)
@@ -2710,6 +2710,7 @@ static struct
   { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" },
   { "Gtk/IMPreeditStyle", "gtk-im-preedit-style" },
   { "Gtk/IMStatusStyle", "gtk-im-status-style" },
+  { "Gtk/Modules", "gtk-modules" },
   { "Gtk/FileChooserBackend", "gtk-file-chooser-backend" },
   { "Gtk/ButtonImages", "gtk-button-images" },
   { "Gtk/MenuImages", "gtk-menu-images" },
index dce2321113b248b2a02e85cf0f7d5e18ea62a0bf..4ebb8c993de9592c104a44d184475015759d708b 100644 (file)
@@ -203,6 +203,7 @@ gtk_public_h_sources =          \
        gtkmenushell.h          \
        gtkmessagedialog.h      \
        gtkmisc.h               \
+       gtkmodules.h            \
        gtknotebook.h           \
        gtkobject.h             \
        gtkoldeditable.h        \
@@ -422,6 +423,7 @@ gtk_c_sources =                 \
        gtkmenushell.c          \
        gtkmessagedialog.c      \
        gtkmisc.c               \
+       gtkmodules.c            \
        gtknotebook.c           \
        gtkobject.c             \
        gtkoldeditable.c        \
index cce4ef82b662ed01298a448ce42cd810e0ddbf4f..c5a982e6a51139cfd099436a000877deba09dda5 100644 (file)
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
 #include <gtk/gtkmenushell.h>
 #include <gtk/gtkmessagedialog.h>
 #include <gtk/gtkmisc.h>
+#include <gtk/gtkmodules.h>
 #include <gtk/gtknotebook.h>
 #include <gtk/gtkobject.h>
 #include <gtk/gtkoldeditable.h>
index 5a5a1ec230c65da69a30e9d68b79a62db07ddbf0..6febf849a921c9fb11ce01834e4b630d5c882f62 100644 (file)
@@ -38,7 +38,8 @@ typedef enum {
   GTK_DEBUG_TREE        = 1 << 3,
   GTK_DEBUG_UPDATES     = 1 << 4,
   GTK_DEBUG_KEYBINDINGS = 1 << 5,
-  GTK_DEBUG_MULTIHEAD   = 1 << 6
+  GTK_DEBUG_MULTIHEAD   = 1 << 6,
+  GTK_DEBUG_MODULES     = 1 << 7
 } GtkDebugFlag;
 
 #ifdef G_ENABLE_DEBUG
index 55df71e992c22c3611a881e583df3993ae4cbea3..7ded97644012a6ed8921dfaa6461eb9f8276aa20 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <gmodule.h>
-#ifdef G_OS_UNIX
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
-#include <sys/types.h>         /* For uid_t, gid_t */
 #endif
+#include <sys/types.h>         /* For uid_t, gid_t */
+
 #ifdef G_OS_WIN32
 #define STRICT
 #include <windows.h>
 #undef STRICT
 #endif
 
-#include <pango/pango-utils.h> /* For pango_split_file_list */
+#include <pango/pango-types.h> /* For pango_language_from_string */
 
 #include "gtkalias.h"
 #include "gtkintl.h"
@@ -59,6 +59,7 @@
 #include "gtkdnd.h"
 #include "gtkversion.h"
 #include "gtkmain.h"
+#include "gtkmodules.h"
 #include "gtkrc.h"
 #include "gtkselection.h"
 #include "gtksettings.h"
@@ -73,7 +74,6 @@ typedef struct _GtkInitFunction                GtkInitFunction;
 typedef struct _GtkQuitFunction                 GtkQuitFunction;
 typedef struct _GtkClosure              GtkClosure;
 typedef struct _GtkKeySnooperData       GtkKeySnooperData;
-typedef struct _GtkModuleInfo            GtkModuleInfo;
 
 struct _GtkInitFunction
 {
@@ -105,12 +105,6 @@ struct _GtkKeySnooperData
   guint id;
 };
 
-struct _GtkModuleInfo
-{
-  GtkModuleInitFunc init_func;
-  GtkModuleDisplayInitFunc display_init_func;
-};
-
 static gint  gtk_quit_invoke_function   (GtkQuitFunction    *quitf);
 static void  gtk_quit_destroy           (GtkQuitFunction    *quitf);
 static gint  gtk_invoke_key_snoopers    (GtkWidget          *grab_widget,
@@ -137,13 +131,6 @@ const guint gtk_micro_version = GTK_MICRO_VERSION;
 const guint gtk_binary_age = GTK_BINARY_AGE;
 const guint gtk_interface_age = GTK_INTERFACE_AGE;
 
-static GSList *gtk_modules;
-
-/* Saved argc,argv for delayed module initialization
- */
-static gint    gtk_argc = 0;
-static gchar **gtk_argv = NULL;
-
 static guint gtk_main_loop_level = 0;
 static gint gtk_initialized = FALSE;
 static GList *current_events = NULL;
@@ -168,7 +155,8 @@ static const GDebugKey gtk_debug_keys[] = {
   {"tree", GTK_DEBUG_TREE},
   {"updates", GTK_DEBUG_UPDATES},
   {"keybindings", GTK_DEBUG_KEYBINDINGS},
-  {"multihead", GTK_DEBUG_MULTIHEAD}
+  {"multihead", GTK_DEBUG_MULTIHEAD},
+  {"modules", GTK_DEBUG_MODULES}
 };
 
 static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
@@ -334,260 +322,6 @@ _gtk_get_data_prefix (void)
 
 #endif /* G_OS_WIN32 */
 
-static gchar **
-get_module_path (void)
-{
-  const gchar *module_path_env;
-  const gchar *exe_prefix;
-  const gchar *home_dir;
-  gchar *home_gtk_dir = NULL;
-  gchar *module_path;
-  gchar *default_dir;
-  static gchar **result = NULL;
-
-  if (result)
-    return result;
-
-  home_dir = g_get_home_dir();
-  if (home_dir)
-    home_gtk_dir = g_build_filename (home_dir, ".gtk-2.0", NULL);
-
-  module_path_env = g_getenv ("GTK_PATH");
-  exe_prefix = g_getenv ("GTK_EXE_PREFIX");
-
-  if (exe_prefix)
-    default_dir = g_build_filename (exe_prefix, "lib", "gtk-2.0", NULL);
-  else
-    default_dir = g_build_filename (GTK_LIBDIR, "gtk-2.0", NULL);
-
-  if (module_path_env && home_gtk_dir)
-    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
-                               module_path_env, home_gtk_dir, default_dir, NULL);
-  else if (module_path_env)
-    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
-                               module_path_env, default_dir, NULL);
-  else if (home_gtk_dir)
-    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
-                               home_gtk_dir, default_dir, NULL);
-  else
-    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
-                               default_dir, NULL);
-
-  g_free (home_gtk_dir);
-  g_free (default_dir);
-
-  result = pango_split_file_list (module_path);
-  g_free (module_path);
-
-  return result;
-}
-
-/**
- * _gtk_get_module_path:
- * @type: the type of the module, for instance 'modules', 'engines', immodules'
- * 
- * Determines the search path for a particular type of module.
- * 
- * Return value: the search path for the module type. Free with g_strfreev().
- **/
-gchar **
-_gtk_get_module_path (const gchar *type)
-{
-  gchar **paths = get_module_path();
-  gchar **path;
-  gchar **result;
-  gint count = 0;
-
-  for (path = paths; *path; path++)
-    count++;
-
-  result = g_new (gchar *, count * 4 + 1);
-
-  count = 0;
-  for (path = get_module_path (); *path; path++)
-    {
-      gint use_version, use_host;
-      
-      for (use_version = TRUE; use_version >= FALSE; use_version--)
-       for (use_host = TRUE; use_host >= FALSE; use_host--)
-         {
-           gchar *tmp_dir;
-           
-           if (use_version && use_host)
-             tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, GTK_HOST, type, NULL);
-           else if (use_version)
-             tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, type, NULL);
-           else if (use_host)
-             tmp_dir = g_build_filename (*path, GTK_HOST, type, NULL);
-           else
-             tmp_dir = g_build_filename (*path, type, NULL);
-
-           result[count++] = tmp_dir;
-         }
-    }
-
-  result[count++] = NULL;
-
-  return result;
-}
-
-/* Like g_module_path, but use .la as the suffix
- */
-static gchar*
-module_build_la_path (const gchar *directory,
-                     const gchar *module_name)
-{
-       gchar *filename;
-       gchar *result;
-       
-       if (strncmp (module_name, "lib", 3) == 0)
-               filename = (gchar *)module_name;
-       else
-               filename =  g_strconcat ("lib", module_name, ".la", NULL);
-
-       if (directory && *directory)
-               result = g_build_filename (directory, filename, NULL);
-       else
-               result = g_strdup (filename);
-
-       if (filename != module_name)
-               g_free (filename);
-
-       return result;
-}
-
-/**
- * _gtk_find_module:
- * @name: the name of the module
- * @type: the type of the module, for instance 'modules', 'engines', immodules'
- * 
- * Looks for a dynamically loadable module named @name of type @type in the
- * standard GTK+ module search path.
- * 
- * Return value: the pathname to the found module, or %NULL if it wasn't found.
- *  Free with g_free().
- **/
-gchar *
-_gtk_find_module (const gchar *name,
-                 const gchar *type)
-{
-  gchar **paths;
-  gchar **path;
-  gchar *module_name = NULL;
-
-  if (g_path_is_absolute (name))
-    return g_strdup (name);
-
-  paths = _gtk_get_module_path (type);
-  for (path = paths; *path; path++)
-    {
-      gchar *tmp_name;
-
-      tmp_name = g_module_build_path (*path, name);
-      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
-       {
-         module_name = tmp_name;
-         goto found;
-       }
-      g_free(tmp_name);
-
-      tmp_name = module_build_la_path (*path, name);
-      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
-       {
-         module_name = tmp_name;
-         goto found;
-       }
-      g_free(tmp_name);
-    }
-
- found:
-  g_strfreev (paths);
-  return module_name;
-}
-
-static GModule *
-find_module (const gchar *name)
-{
-  GModule *module;
-  gchar *module_name;
-
-  module_name = _gtk_find_module (name, "modules");
-  if (!module_name)
-    {
-      /* As last resort, try loading without an absolute path (using system
-       * library path)
-       */
-      module_name = g_module_build_path (NULL, name);
-    }
-  
-  module = g_module_open (module_name, G_MODULE_BIND_LAZY);
-  g_free(module_name);
-
-  return module;
-}
-
-static GSList *
-load_module (GSList      *module_list,
-            const gchar *name)
-{
-  GtkModuleInitFunc modinit_func = NULL;
-  GtkModuleInfo *info;
-  GModule *module = NULL;
-  
-  if (g_module_supported ())
-    {
-      module = find_module (name);
-      if (module &&
-         g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) &&
-         modinit_func)
-       {
-         if (!g_slist_find (module_list, (gconstpointer) modinit_func))
-           {
-             g_module_make_resident (module);
-             info = g_new (GtkModuleInfo, 1);
-
-             info->init_func = modinit_func;
-             g_module_symbol (module, "gtk_module_display_init",
-                              (gpointer *) &info->display_init_func);
-             
-             module_list = g_slist_prepend (module_list, info);
-           }
-         else
-           {
-             g_module_close (module);
-             module = NULL;
-           }
-       }
-    }
-  if (!modinit_func)
-    {
-      g_message ("Failed to load module \"%s\": %s",
-                module ? g_module_name (module) : name,
-                g_module_error ());
-      if (module)
-       g_module_close (module);
-    }
-  
-  return module_list;
-}
-
-static GSList *
-load_modules (const char *module_str)
-{
-  gchar **module_names = pango_split_file_list (module_str);
-  GSList *module_list = NULL;
-  gint i;
-  
-  for (i = 0; module_names[i]; i++)
-    module_list = load_module (module_list, module_names[i]);
-  
-  module_list = g_slist_reverse (module_list);
-  
-  g_strfreev (module_names);
-
-  return module_list;
-}
-
 static gboolean do_setlocale = TRUE;
 
 /**
@@ -614,51 +348,6 @@ gtk_disable_setlocale (void)
 #undef gtk_init_check
 #endif
 
-static void
-default_display_notify_cb (GdkDisplayManager *display_manager)
-{
-  GSList *slist;
-
-  /* Initialize non-multihead-aware modules when the
-   * default display is first set to a non-NULL value.
-   */
-  static gboolean initialized = FALSE;
-
-  if (!gdk_display_get_default () || initialized)
-    return;
-
-  initialized = TRUE;
-
-  for (slist = gtk_modules; slist; slist = slist->next)
-    {
-      if (slist->data)
-       {
-         GtkModuleInfo *info = slist->data;
-
-         if (!info->display_init_func)
-           info->init_func (&gtk_argc, &gtk_argv);
-       }
-    }
-}
-
-static void
-display_opened_cb (GdkDisplayManager *display_manager,
-                  GdkDisplay        *display)
-{
-  GSList *slist;
-  
-  for (slist = gtk_modules; slist; slist = slist->next)
-    {
-      if (slist->data)
-       {
-         GtkModuleInfo *info = slist->data;
-
-         if (info->display_init_func)
-           info->display_init_func (display);
-       }
-    }
-}
-
 /**
  * gtk_parse_args:
  * @argc: a pointer to the number of command line arguments.
@@ -681,8 +370,6 @@ gtk_parse_args (int    *argc,
                char ***argv)
 {
   GString *gtk_modules_string = NULL;
-  GSList *slist;
-  GdkDisplayManager *display_manager;
   const gchar *env_string;
 
   if (gtk_initialized)
@@ -747,8 +434,8 @@ gtk_parse_args (int    *argc,
                {
                  if (gtk_modules_string)
                    g_string_append_c (gtk_modules_string, G_SEARCHPATH_SEPARATOR);
-                 else
-                   gtk_modules_string = g_string_new (NULL);
+                 else
+                   gtk_modules_string = g_string_new (NULL);
 
                  g_string_append (gtk_modules_string, module_name);
                }
@@ -823,23 +510,11 @@ gtk_parse_args (int    *argc,
              *argc -= k;
            }
        }
-
-      gtk_argv = g_malloc ((gtk_argc + 1) * sizeof (char*));
-      for (i = 0; i < gtk_argc; i++)
-       gtk_argv[i] = g_strdup ((*argv)[i]);
-      gtk_argv[gtk_argc] = NULL;
     }
 
   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
     gdk_window_set_debug_updates (TRUE);
 
-  /* load gtk modules */
-  if (gtk_modules_string)
-    {
-      gtk_modules = load_modules (gtk_modules_string->str);
-      g_string_free (gtk_modules_string, TRUE);
-    }
-
 #ifdef ENABLE_NLS
   bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
   bindtextdomain (GETTEXT_PACKAGE "-properties", GTK_LOCALEDIR);
@@ -866,30 +541,19 @@ gtk_parse_args (int    *argc,
   gtk_type_init (0);
   _gtk_accel_map_init ();  
   _gtk_rc_init ();
-  
+
   /* Set the 'initialized' flag.
    */
   gtk_initialized = TRUE;
 
-  display_manager = gdk_display_manager_get ();
-  g_signal_connect (display_manager, "notify::default-display",
-                   G_CALLBACK (default_display_notify_cb), NULL);
-  g_signal_connect (display_manager, "display-opened",
-                   G_CALLBACK (display_opened_cb), NULL);
-
-  /* initialize multhead aware gtk modules; for other modules,
-   * we wait until we have a display open;
-   */
-  for (slist = gtk_modules; slist; slist = slist->next)
+  /* load gtk modules */
+  if (gtk_modules_string)
     {
-      if (slist->data)
-       {
-         GtkModuleInfo *info = slist->data;
-
-         if (info->display_init_func)
-           info->init_func (argc, argv);
-       }
+      _gtk_modules_init (argc, argv, gtk_modules_string->str);
+      g_string_free (gtk_modules_string, TRUE);
     }
+  else
+    _gtk_modules_init (argc, argv, "");
   
   return TRUE;
 }
index 06d15f76db13344c76b07a5f331cbc89afc241b7..03d0bf38b7545ee6395cd1e7f83c48dcbb72fdd2 100644 (file)
@@ -57,9 +57,6 @@ extern "C" {
 
 #endif /* GTK_DISABLE_DEPRECATED */
 
-typedef void   (*GtkModuleInitFunc)        (gint         *argc,
-                                            gchar      ***argv);
-typedef void   (*GtkModuleDisplayInitFunc) (GdkDisplay   *display);
 typedef gint   (*GtkKeySnoopFunc)          (GtkWidget    *grab_widget,
                                             GdkEventKey  *event,
                                             gpointer      func_data);
@@ -214,10 +211,6 @@ gboolean _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
                                    const GValue          *handler_return,
                                    gpointer               dummy);
 
-gchar * _gtk_find_module     (const gchar *name,
-                             const gchar *type);
-gchar **_gtk_get_module_path (const gchar *type);
-
 gchar *_gtk_get_lc_ctype (void);
 
 #ifdef __cplusplus
diff --git a/gtk/gtkmodules.c b/gtk/gtkmodules.c
new file mode 100644 (file)
index 0000000..51718c8
--- /dev/null
@@ -0,0 +1,540 @@
+/* GTK - The GIMP Toolkit
+ * Copyright 1998-2002 Tim Janik, Red Hat, Inc., and others.
+ * Copyright (C) 2003 Alex Graveley
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "gtkmodules.h"
+#include "gtksettings.h"
+#include "gtkdebug.h"
+
+#include <gmodule.h>
+#include <pango/pango-utils.h> /* For pango_split_file_list */
+
+typedef struct _GtkModuleInfo GtkModuleInfo;
+struct _GtkModuleInfo
+{
+  GModule                 *module;
+  gint                     ref_count;
+  GtkModuleInitFunc        init_func;
+  GtkModuleDisplayInitFunc display_init_func;
+  GSList                  *names;
+};
+
+static GSList *gtk_modules = NULL;
+
+static gboolean default_display_opened = FALSE;
+
+/* Saved argc, argv for delayed module initialization
+ */
+static gint    gtk_argc = 0;
+static gchar **gtk_argv = NULL;
+
+static gchar **
+get_module_path (void)
+{
+  const gchar *module_path_env;
+  const gchar *exe_prefix;
+  const gchar *home_dir;
+  gchar *home_gtk_dir = NULL;
+  gchar *module_path;
+  gchar *default_dir;
+  static gchar **result = NULL;
+
+  if (result)
+    return result;
+
+  home_dir = g_get_home_dir();
+  if (home_dir)
+    home_gtk_dir = g_build_filename (home_dir, ".gtk-2.0", NULL);
+
+  module_path_env = g_getenv ("GTK_PATH");
+  exe_prefix = g_getenv ("GTK_EXE_PREFIX");
+
+  if (exe_prefix)
+    default_dir = g_build_filename (exe_prefix, "lib", "gtk-2.0", NULL);
+  else
+    default_dir = g_build_filename (GTK_LIBDIR, "gtk-2.0", NULL);
+
+  if (module_path_env && home_gtk_dir)
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+                               module_path_env, home_gtk_dir, default_dir, NULL);
+  else if (module_path_env)
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+                               module_path_env, default_dir, NULL);
+  else if (home_gtk_dir)
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+                               home_gtk_dir, default_dir, NULL);
+  else
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+                               default_dir, NULL);
+
+  g_free (home_gtk_dir);
+  g_free (default_dir);
+
+  result = pango_split_file_list (module_path);
+  g_free (module_path);
+
+  return result;
+}
+
+/**
+ * _gtk_get_module_path:
+ * @type: the type of the module, for instance 'modules', 'engines', immodules'
+ * 
+ * Determines the search path for a particular type of module.
+ * 
+ * Return value: the search path for the module type. Free with g_strfreev().
+ **/
+gchar **
+_gtk_get_module_path (const gchar *type)
+{
+  gchar **paths = get_module_path();
+  gchar **path;
+  gchar **result;
+  gint count = 0;
+
+  for (path = paths; *path; path++)
+    count++;
+
+  result = g_new (gchar *, count * 4 + 1);
+
+  count = 0;
+  for (path = get_module_path (); *path; path++)
+    {
+      gint use_version, use_host;
+      
+      for (use_version = TRUE; use_version >= FALSE; use_version--)
+       for (use_host = TRUE; use_host >= FALSE; use_host--)
+         {
+           gchar *tmp_dir;
+           
+           if (use_version && use_host)
+             tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, GTK_HOST, type, NULL);
+           else if (use_version)
+             tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, type, NULL);
+           else if (use_host)
+             tmp_dir = g_build_filename (*path, GTK_HOST, type, NULL);
+           else
+             tmp_dir = g_build_filename (*path, type, NULL);
+
+           result[count++] = tmp_dir;
+         }
+    }
+
+  result[count++] = NULL;
+
+  return result;
+}
+
+/* Like g_module_path, but use .la as the suffix
+ */
+static gchar*
+module_build_la_path (const gchar *directory,
+                     const gchar *module_name)
+{
+  gchar *filename;
+  gchar *result;
+       
+  if (strncmp (module_name, "lib", 3) == 0)
+    filename = (gchar *)module_name;
+  else
+    filename =  g_strconcat ("lib", module_name, ".la", NULL);
+
+  if (directory && *directory)
+    result = g_build_filename (directory, filename, NULL);
+  else
+    result = g_strdup (filename);
+
+  if (filename != module_name)
+    g_free (filename);
+
+  return result;
+}
+
+/**
+ * _gtk_find_module:
+ * @name: the name of the module
+ * @type: the type of the module, for instance 'modules', 'engines', immodules'
+ * 
+ * Looks for a dynamically module named @name of type @type in the standard GTK+
+ *  module search path.
+ * 
+ * Return value: the pathname to the found module, or %NULL if it wasn't found.
+ *  Free with g_free().
+ **/
+gchar *
+_gtk_find_module (const gchar *name,
+                 const gchar *type)
+{
+  gchar **paths;
+  gchar **path;
+  gchar *module_name = NULL;
+
+  if (g_path_is_absolute (name))
+    return g_strdup (name);
+
+  paths = _gtk_get_module_path (type);
+  for (path = paths; *path; path++)
+    {
+      gchar *tmp_name;
+
+      tmp_name = g_module_build_path (*path, name);
+      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
+       {
+         module_name = tmp_name;
+         goto found;
+       }
+      g_free(tmp_name);
+
+      tmp_name = module_build_la_path (*path, name);
+      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
+       {
+         module_name = tmp_name;
+         goto found;
+       }
+      g_free(tmp_name);
+    }
+
+ found:
+  g_strfreev (paths);
+  return module_name;
+}
+
+static GModule *
+find_module (const gchar *name)
+{
+  GModule *module;
+  gchar *module_name;
+
+  module_name = _gtk_find_module (name, "modules");
+  if (!module_name)
+    {
+      /* As last resort, try loading without an absolute path (using system
+       * library path)
+       */
+      module_name = g_module_build_path (NULL, name);
+    }
+
+  module = g_module_open (module_name, G_MODULE_BIND_LAZY);
+  g_free(module_name);
+
+  return module;
+}
+
+static gint
+cmp_module (GtkModuleInfo *info,
+           GModule       *module)
+{
+  return info->module != module;
+}
+
+static GSList *
+load_module (GSList      *module_list,
+            const gchar *name)
+{
+  GtkModuleInitFunc modinit_func;
+  GtkModuleInfo *info = NULL;
+  GModule *module = NULL;
+  GSList *l;
+  gboolean success = FALSE;
+  
+  if (g_module_supported ())
+    {
+      for (l = gtk_modules; l; l = l->next)
+       {
+         info = l->data;
+         if (g_slist_find_custom (info->names, name, 
+                                  (GCompareFunc)strcmp))
+           {
+             info->ref_count++;
+             
+             success = TRUE;
+           }
+       }
+
+      if (!success) 
+       {
+         module = find_module (name);
+
+         if (module)
+           {
+             if (!g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) ||
+                 !modinit_func)
+               g_module_close (module);
+             else
+               {
+                 success = TRUE;
+                 info = (GtkModuleInfo *) g_slist_find_custom (gtk_modules, module,
+                                                               (GCompareFunc)cmp_module);
+                 if (!info)
+                   {
+                     info = g_new0 (GtkModuleInfo, 1);
+                     
+                     info->names = g_slist_prepend (info->names, g_strdup (name));
+                     info->module = module;
+                     info->ref_count = 1;
+                     info->init_func = modinit_func;
+                     g_module_symbol (module, "gtk_module_display_init",
+                                      (gpointer *) &info->display_init_func);
+                     
+                     gtk_modules = g_slist_prepend (gtk_modules, info);
+                     
+                     /* display_init == NULL indicates a non-multihead aware module.
+                      * For these, we delay the call to init_func until first display is 
+                      * opened, see default_display_notify_cb().
+                      * For multihead aware modules, we call init_func immediately,
+                      * and also call display_init_func on all opened displays.
+                      */
+                     if (default_display_opened || info->display_init_func)
+                       (* info->init_func) (&gtk_argc, &gtk_argv);
+                     
+                     if (info->display_init_func) 
+                       {
+                         GSList *displays, *iter;                
+                         displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
+                         for (iter = displays; iter; iter = iter->next)
+                           {
+                             GdkDisplay *display = iter->data;
+                         (* info->display_init_func) (display);
+                           }
+                         g_slist_free (displays);
+                       }
+                   }
+                 else
+                   {
+                     GTK_NOTE (MODULES, g_print ("Module already loaded, ignoring: %s\n", name));
+                     info->names = g_slist_prepend (info->names, g_strdup (name));
+                     info->ref_count++;
+                     /* remove new reference count on module, we already have one */
+                     g_module_close (module);
+                   }
+               }
+           }
+       }
+    }
+
+  if (success)
+    {
+      if (!g_slist_find (module_list, info))
+       {
+         module_list = g_slist_prepend (module_list, info);
+       }
+    }
+  else
+    g_message ("Failed to load module \"%s\": %s", name, g_module_error ());
+  
+  return module_list;
+}
+
+
+static void
+gtk_module_info_unref (GtkModuleInfo *info)
+{
+  GSList *l;
+
+  info->ref_count--;
+
+  if (info->ref_count == 0) 
+    {
+      GTK_NOTE (MODULES, 
+               g_print ("Unloading module: %s", g_module_name (info->module)));
+
+      gtk_modules = g_slist_remove (gtk_modules, info);
+      g_module_close (info->module);
+      for (l = info->names; l; l = l->next)
+       g_free (l->data);
+      g_slist_free (info->names);
+      g_free (info);
+    }
+}
+
+static GSList *
+load_modules (const char *module_str)
+{
+  gchar **module_names;
+  GSList *module_list = NULL;
+  gint i;
+
+  GTK_NOTE (MODULES, g_print ("Loading module list: %s", module_str));
+
+  module_names = pango_split_file_list (module_str);
+  for (i = 0; module_names[i]; i++) 
+    module_list = load_module (module_list, module_names[i]);
+
+  module_list = g_slist_reverse (module_list);
+  g_strfreev (module_names);
+
+  return module_list;
+}
+
+static void
+default_display_notify_cb (GdkDisplayManager *display_manager)
+{
+  GSList *slist;
+
+  /* Initialize non-multihead-aware modules when the
+   * default display is first set to a non-NULL value.
+   */
+
+  if (!gdk_display_get_default () || default_display_opened)
+    return;
+
+  default_display_opened = TRUE;
+
+  for (slist = gtk_modules; slist; slist = slist->next)
+    {
+      if (slist->data)
+       {
+         GtkModuleInfo *info = slist->data;
+
+         if (!info->display_init_func)
+           (* info->init_func) (&gtk_argc, &gtk_argv);
+       }
+    }
+}
+
+static void
+display_closed_cb (GdkDisplay *display,
+                  gboolean    is_error)
+{
+  GdkScreen *screen;
+  GtkSettings *settings;
+  gint i;
+
+  for (i = 0; i < gdk_display_get_n_screens (display); i++)
+    {
+      screen = gdk_display_get_screen (display, i);
+
+      settings = gtk_settings_get_for_screen (screen);
+
+      g_object_set_data_full (G_OBJECT (settings),
+                             "gtk-modules",
+                             NULL, NULL);
+    }  
+}
+                  
+
+static void
+display_opened_cb (GdkDisplayManager *display_manager,
+                  GdkDisplay        *display)
+{
+  GSList *slist;
+  GdkScreen *screen;
+  GtkSettings *settings;
+  gint i;
+
+  for (slist = gtk_modules; slist; slist = slist->next)
+    {
+      if (slist->data)
+       {
+         GtkModuleInfo *info = slist->data;
+
+         if (info->display_init_func)
+           (* info->display_init_func) (display);
+       }
+    }
+  
+  for (i = 0; i < gdk_display_get_n_screens (display); i++)
+    {
+      GValue value = { 0, };
+
+      g_value_init (&value, G_TYPE_STRING);
+
+      screen = gdk_display_get_screen (display, i);
+
+      if (gdk_screen_get_setting (screen, "gtk-modules", &value))
+       {
+         settings = gtk_settings_get_for_screen (screen);
+         _gtk_modules_settings_changed (settings, g_value_get_string (&value));
+         g_value_unset (&value);
+       }
+    }
+
+  /* Since closing display doesn't actually release the resources yet,
+   * we have to connect to the ::closed signal.
+   */
+  g_signal_connect (display, "closed", G_CALLBACK (display_closed_cb), NULL);
+}
+
+void
+_gtk_modules_init (gint        *argc, 
+                  gchar     ***argv, 
+                  const gchar *gtk_modules_args)
+{
+  GdkDisplayManager *display_manager;
+  gint i;
+
+  g_assert (gtk_argv == NULL);
+
+  if (argc && argv) 
+    {
+      /* store argc and argv for later use in mod initialization */
+      gtk_argc = *argc;
+      gtk_argv = g_new (gchar *, *argc + 1);
+      for (i = 0; i < gtk_argc; i++)
+       gtk_argv [i] = g_strdup ((*argv) [i]);
+      gtk_argv [*argc] = NULL;
+    }
+
+  display_manager = gdk_display_manager_get ();
+  g_signal_connect (display_manager, "notify::default-display",
+                   G_CALLBACK (default_display_notify_cb), 
+                   NULL);
+  g_signal_connect (display_manager, "display-opened",
+                   G_CALLBACK (display_opened_cb), 
+                   NULL);
+
+  /* Modules specified in the GTK_MODULES environment variable
+   * or on the command line are always loaded, so we'll just leak 
+   * the refcounts.
+   */
+  g_slist_free (load_modules (gtk_modules_args));
+}
+
+static void
+settings_destroy_notify (gpointer data)
+{
+  GSList *iter, *modules = data;
+
+  for (iter = modules; iter; iter = iter->next) 
+    {
+      GtkModuleInfo *info = iter->data;
+      gtk_module_info_unref (info);
+    }
+  g_slist_free (modules);
+}
+
+void
+_gtk_modules_settings_changed (GtkSettings *settings, 
+                              const gchar *modules)
+{
+  GSList *new_modules = NULL;
+
+  /* load/ref before unreffing existing */
+  if (modules && modules[0])
+    new_modules = load_modules (modules);
+
+  g_object_set_data_full (G_OBJECT (settings),
+                         "gtk-modules",
+                         new_modules,
+                         settings_destroy_notify);
+}
diff --git a/gtk/gtkmodules.h b/gtk/gtkmodules.h
new file mode 100644 (file)
index 0000000..c7ebd39
--- /dev/null
@@ -0,0 +1,50 @@
+/* GTK - The GIMP Toolkit
+ * Copyright 1998-2002 Tim Janik, Red Hat, Inc., and others.
+ * Copyright (C) 2003 Alex Graveley
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_MODULES_H__
+#define __GTK_MODULES_H__
+
+#include <gtk/gtksettings.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Functions for use within GTK+
+ */
+gchar * _gtk_find_module        (const gchar *name,
+                                const gchar *type);
+gchar **_gtk_get_module_path    (const gchar *type);
+
+void    _gtk_modules_init             (gint         *argc,
+                                      gchar      ***argv,
+                                      const gchar  *gtk_modules_args);
+void    _gtk_modules_settings_changed (GtkSettings  *settings, 
+                                      const gchar  *modules);
+
+typedef void    (*GtkModuleInitFunc)        (gint        *argc,
+                                             gchar      ***argv);
+typedef void    (*GtkModuleDisplayInitFunc) (GdkDisplay   *display);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __GTK_MODULES_H__ */
index cf4a7772f39894e0c5cf5891e018c582dddf054f..0767b35e245b5527855c23f4003cb8ffb1287904 100644 (file)
@@ -63,6 +63,7 @@ enum {
   PROP_DND_DRAG_THRESHOLD,
   PROP_FONT_NAME,
   PROP_ICON_SIZES,
+  PROP_MODULES,
   PROP_XFT_ANTIALIAS,
   PROP_XFT_HINTING,
   PROP_XFT_HINTSTYLE,
@@ -89,6 +90,8 @@ static guint  settings_install_property_parser (GtkSettingsClass      *class,
                                                  GParamSpec            *pspec,
                                                  GtkRcPropertyParser    parser);
 static void    settings_update_double_click      (GtkSettings           *settings);
+static void    settings_update_modules           (GtkSettings           *settings);
+
 
 
 /* --- variables --- */
@@ -360,6 +363,15 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                              NULL);
   g_assert (result == PROP_ICON_SIZES);
 
+  result = settings_install_property_parser (class,
+                                             g_param_spec_string ("gtk-modules",
+                                                                 P_("GTK Modules"),
+                                                                 P_("List of currently active GTK modules"),
+                                                                 NULL,
+                                                                 G_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_MODULES);
+
 #ifdef GDK_WINDOWING_X11
   result = settings_install_property_parser (class,
                                             g_param_spec_int ("gtk-xft-antialias",
@@ -584,6 +596,9 @@ gtk_settings_notify (GObject    *object,
 
   switch (property_id)
     {
+    case PROP_MODULES:
+      settings_update_modules (settings);
+      break;
     case PROP_DOUBLE_CLICK_TIME:
     case PROP_DOUBLE_CLICK_DISTANCE:
       settings_update_double_click (settings);
@@ -1363,3 +1378,18 @@ settings_update_double_click (GtkSettings *settings)
       gdk_display_set_double_click_distance (display, double_click_distance);
     }
 }
+
+static void
+settings_update_modules (GtkSettings *settings)
+{
+  GdkDisplay *display = gdk_screen_get_display (settings->screen);
+  gchar *modules;
+  
+  g_object_get (settings, 
+               "gtk-modules", &modules,
+               NULL);
+  
+  _gtk_modules_settings_changed (settings, modules);
+  
+  g_free (modules);
+}